package codegen.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import codegen.config.exception.ConfigurationException;
import codegen.config.validator.ConfigValidator;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * 配置管理器
 * 负责管理配置文件的读取、验证、更新和保存操作。
 * 主要功能：
 * 1. 加载配置文件并验证其有效性
 * 2. 提供配置的查询和修改接口
 * 3. 保存配置到文件系统
 * 4. 支持自定义配置文件路径
 *
 * @author codegen
 * @since 1.0.0
 */
public class ConfigurationManager {
    /** 默认配置文件路径 */
    private static final String DEFAULT_CONFIG_PATH = "src/main/resources/config.json";
    /** JSON对象映射器 */
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /** 当前加载的配置对象 */
    private Configuration configuration;
    /** 当前使用的配置文件路径 */
    private String configPath;

    /**
     * 使用默认配置文件路径创建配置管理器
     * 默认路径为：src/main/resources/config.json
     */
    public ConfigurationManager() {
        this(DEFAULT_CONFIG_PATH);
    }

    /**
     * 使用指定的配置文件路径创建配置管理器
     *
     * @param configPath 配置文件的路径
     * @throws ConfigurationException 当配置文件不存在或无法加载时抛出
     */
    public ConfigurationManager(String configPath) {
        this.configPath = configPath;
        loadConfiguration();
    }

    /**
     * 加载配置文件
     * 从指定路径加载配置文件，并进行有效性验证。
     * 如果配置文件不存在或格式错误，将抛出异常。
     *
     * @throws ConfigurationException 当配置文件不存在、格式错误或验证失败时抛出
     */
    public void loadConfiguration() {
        try {
            // 检查配置文件是否存在
            Path path = Paths.get(configPath);
            if (!Files.exists(path)) {
                throw new ConfigurationException("配置文件不存在：" + configPath);
            }

            // 读取并解析配置文件
            configuration = OBJECT_MAPPER.readValue(path.toFile(), Configuration.class);

            // 验证配置有效性
            ConfigValidator.validate(configuration);
        } catch (IOException e) {
            throw new ConfigurationException("加载配置文件失败：" + e.getMessage(), e);
        }
    }

    /**
     * 保存配置
     * 将当前配置对象保存到文件系统。
     * 保存前会先验证配置的有效性。
     *
     * @throws ConfigurationException 当配置验证失败或保存失败时抛出
     */
    public void saveConfiguration() {
        try {
            // 保存前验证配置
            ConfigValidator.validate(configuration);

            // 使用美化输出格式保存配置
            OBJECT_MAPPER.writerWithDefaultPrettyPrinter()
                    .writeValue(new File(configPath), configuration);
        } catch (IOException e) {
            throw new ConfigurationException("保存配置文件失败：" + e.getMessage(), e);
        }
    }

    /**
     * 更新配置
     * 使用新的配置对象替换当前配置，并保存到文件系统。
     * 更新前会验证新配置的有效性。
     *
     * @param newConfig 新的配置对象
     * @throws ConfigurationException 当新配置验证失败或保存失败时抛出
     */
    public void updateConfiguration(Configuration newConfig) {
        // 验证新配置的有效性
        ConfigValidator.validate(newConfig);

        // 更新配置对象
        this.configuration = newConfig;

        // 保存到文件系统
        saveConfiguration();
    }

    /**
     * 获取当前配置对象
     *
     * @return 当前加载的配置对象
     */
    public Configuration getConfiguration() {
        return configuration;
    }

    /**
     * 获取当前使用的配置文件路径
     *
     * @return 配置文件的路径
     */
    public String getConfigPath() {
        return configPath;
    }
}
